package cn.sunxyz.idea.demo.proxy;

import cn.sunxyz.idea.demo.aspect.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Created by yangrd on 2017/5/25.
 */
public class ProxyFactory {

    /**
     * key :=> 排序字段, value :=> Aspect 优先推荐此接口
     */
    public static <T> T getProxy(Class<T> cls, Map<Integer, Aspect> sortAspects) {
        return getProxy(cls, sortAspects.entrySet().stream().map(sortEntry -> sortEntry.getValue()).collect(Collectors.toList()));
    }

    /**
     * aspects 最好已经排序 此处不负责排序
     */
    public static <T> T getProxy(Class<T> cls, Collection<Aspect> aspects) {
        if (aspects != null) {
            List<AdviceAspect> adviceAspects = new ArrayList<>();
            List<InvocationHandler> invocationHandlers = new ArrayList<>();
            for (Aspect aspect : aspects) {
                if (aspect instanceof AdviceAspect) {
                    adviceAspects.add((AdviceAspect) aspect);
                } else if (aspect instanceof InvocationHandler) {
                    invocationHandlers.add((InvocationHandler) aspect);
                }
            }
            //将两个代理模式进行串联 handlerProxy -> adviceProxy
            AdviceProxy adviceProxy = ProxyManger.getProxy(ProxyManger.Singleton.ADVICE_PROXY);
            adviceProxy.addAdviceAspectAll(adviceAspects);
            //提供代理的适配器
            InvocationHandler invocationHandlerAdapter = new InvocationHandlerAdapter(adviceProxy);
            //此处多了一层默认代理 -> 链表
            InvocationHandler defaultInvocationHandler = new AbstractInvocationHandler() {
            };
            InvocationHandler lastInvocationHandler = defaultInvocationHandler;
            for (InvocationHandler handler : invocationHandlers) {
                lastInvocationHandler.setHandler(handler);
                lastInvocationHandler = handler;
            }
            lastInvocationHandler.setHandler(invocationHandlerAdapter);
            HandlerProxy handlerProxy = ProxyManger.getProxy(ProxyManger.Singleton.HANDLER_PROXY);
            handlerProxy.setInvocationHandler(defaultInvocationHandler);//设置默认的InvocationHandler
            return handlerProxy.getProxy(cls);
        }
        return null;
    }

    static class InvocationHandlerAdapter extends AbstractInvocationHandler {
        private AdviceProxy adviceProxy;

        public InvocationHandlerAdapter(AdviceProxy adviceProxy) {
            this.adviceProxy = adviceProxy;
        }

        @Override
        public Object handlerInvocation(Invocation invocation) throws Throwable {
            return adviceProxy.intercept(invocation.obj, invocation.method, invocation.args, invocation.proxy);
        }
    }

}
